/*
 * $Log: TrainingModelLayer.java,v $ Revision 1.2 2006/11/05 13:58:00 wetzker
 * more merging - CLang + MF + some states still missing
 * 
 * Revision 1.1.28.1 2006/07/26 15:28:26 endert Formatted Code
 * 
 * Revision 1.1 2006/03/13 07:37:41 axle moved from ROOT/src for Maven 2
 * Buildsystem and Team/Soccerscope separation
 * 
 * Revision 1.4 2006/03/07 12:46:23 endert Merge after refactoring: - New
 * State-Interface: One Method for each action type - Action Bean removed -
 * ActionFactorys for helper methods, States calculate main-Action themselves -
 * formatted code - added State-List in Monitor (Context-Menu of Player) - other
 * smaller stuff
 * 
 * Revision 1.3.2.1 2006/02/25 22:07:03 wetzker formated
 * 
 * Revision 1.3 2006/02/22 16:05:01 endert This is done: - Rebound SoccerScope
 * to Agents (can be added or removed in config-file) - Situations now all
 * extend abstract class Situation - Refactorings: ActionBean _ removed from
 * Attributes - SoccerScope will automatically connect to host given in
 * Start-Call - Trainer uses the same host as soccerscope - Removed unused stuff
 * (old confs, bat, etc.) - Code formatted (good luck when merging) - organized
 * imports - all that i forgot to mention here
 * 
 * Revision 1.2 2005/10/25 20:51:34 endert Added Training-Editor to SoccerScope,
 * restructuring in some old classes and some experimental stuff (goals,
 * commitments, mental model)
 * 
 * Revision 1.1.2.2 2005/10/11 18:32:28 endert Adoptions because of moved
 * TrainingModel
 * 
 * Revision 1.1.2.1 2005/10/10 11:05:07 endert New Training-Scenario Editor!
 * There exists a dialog, which opens on middle-mouse click on the field. From
 * here, the Trainings-Scenario may be specified in a more comfortable manner.
 * The Trainings-Scenario is also visualized on the Field - using the
 * TrainingModelLayer. The TrainingModel itself contains all data specified in
 * the scenario, and therefor can be serialized to HDD, using an XML-Stream
 * generator (XStream). The Scenario editor is still under development.
 * 
 * Revision 1.16 2005/10/01 13:46:17 wetzker organized playersmodel and removed
 * all unsed methods - redifined offside as the y-coordinate of the last
 * opponent but the goalie added predicted interception time to gui added new
 * dashToPoint-version with given time for reaching point added dynamic-depth to
 * pass calculation as it seems very time consuming improved collision with ball
 * model
 * 
 * Revision 1.15 2005/09/01 17:30:32 thyrion added quick'n'dirty display of
 * opponentinterceptionpoint
 * 
 * Revision 1.14 2005/09/01 08:29:08 andpaul added: showing actual player state
 * in WorldModelLayer (on the right site of the playing field)
 * 
 * Revision 1.13 2005/08/16 16:26:49 wetzker merged composite branch
 * 
 * Revision 1.11.2.6 2005/08/16 15:43:29 wetzker removed ball and player cloning
 * in getSelf, getBall -> should be much faster now merged with changes from
 * head
 * 
 * Revision 1.11.2.5 2005/07/20 17:59:02 wetzker new StateValues, AB +
 * fastDribbling (by now only in BodyDir), + started InterceptBallSituation
 * 
 * Revision 1.11.2.4 2005/07/18 09:00:07 wetzker debugged: - shootGoal, now
 * working quiet well (but still only a workaround) - attackInLine - bodyCycle()
 * was wrong :/ - dribbling added: - stamina management, use
 * p.correctDashPower(StaminaLevel) moved: - ControllerNumbers, as they aren't
 * use solo by the connection
 * 
 * Revision 1.11.2.3 2005/07/15 19:53:45 wetzker added offside line
 * 
 * Revision 1.11.2.2 2005/07/15 19:19:38 wetzker debugged NPE
 * 
 * Revision 1.11.2.1 2005/07/14 16:53:53 wetzker + speed in AgentWM is displayed
 * 
 * Revision 1.11 2005/07/04 17:10:42 thyrion workaround if cycle < 0
 * 
 * Revision 1.10 2005/06/24 21:29:37 wetzker changes in Agent.WM.Visualization -
 * shadows now got numbers - goalies differ in color
 * 
 * Revision 1.9 2005/06/20 22:21:18 andpaul added: show and save body direction
 * of wm players
 * 
 * Revision 1.8 2005/06/20 21:57:47 andpaul added: store and show reliable flag
 * 
 * Revision 1.7 2005/06/19 23:40:50 wetzker added IP
 * 
 * Revision 1.6 2005/06/19 19:44:37 till added parameter teamSide to constructor
 * of soccerscope.model.Player
 * 
 * Revision 1.5 2005/06/15 18:14:33 haeder removed unused imports
 * 
 * Revision 1.4 2005/06/15 17:03:38 wetzker removed JIAC from Head + changes in
 * framework please report bugs or shortcomings some scenarios might not work
 * because of wrong imports
 * 
 * Revision 1.2.2.1 2005/06/15 16:45:01 wetzker final version
 * 
 * Revision 1.3 2005/06/12 18:52:17 thyrion fixed saving&loading of our
 * worldmodel (to load first open server log)
 * 
 * Revision 1.2 2005/05/19 15:35:26 wetzker + IP shown in GUI (use AgentWM)
 * 
 * Revision 1.1 2005/04/20 10:38:40 endert Fresh Team Repository installation
 * from /home/e/endert/Robocup to here.
 * 
 * Revision 1.3 2005/02/06 07:20:08 maketi Added soccerscope with connection to
 * our world model
 * 
 * Revision 1.3 2002/10/10 09:43:40 koji ͥ*�ΰ�η׻��β���
 * (Direction-Distance Table)
 * 
 * Revision 1.2 2002/10/04 10:39:23 koji
 * Tuple,Point,Vector�Υѥå������ѹ���Geometry,Circle,Line,Rectangle�ɲ�
 * 
 * Revision 1.1 2002/10/01 14:11:13 koji support Preference, gif format
 * 
 * Revision 1.3 2002/09/12 15:28:32 koji
 * ������%����?���ɲ�,ColorTool��Color2�����
 * 
 * Revision 1.2 2002/09/02 07:06:29 taku-ako
 * Geometry��Ϣ�Υ饤�֥����.
 * 
 * Revision 1.1.1.1 2002/03/01 14:12:53 koji CVS�����
 * 
 */

package soccerscope.view.layer;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Arrays;

import soccerscope.model.Ball;
import soccerscope.model.Player;
import soccerscope.model.SoccerObject;
import soccerscope.model.SoccerObjectID;
import soccerscope.model.Team;
import soccerscope.model.WorldModel;
import soccerscope.training.ObjectTrainingModel;
import soccerscope.training.PlayerTrainingModel;
import soccerscope.training.TrainingModel;
import soccerscope.training.ObjectTrainingModel.POSITION_TYPE;
import soccerscope.util.Color2;
import soccerscope.util.geom.Point2f;
import soccerscope.util.geom.Tuple2f;
import soccerscope.view.FieldPane;
import soccerscope.view.SoccerObjectSelectObserver;

public class TrainingModelLayer
    extends Layer
    implements SoccerObjectSelectObserver, SoccerObjectID {

  private boolean selected[] = new boolean[SoccerObjectID.MAX_ID];

  public TrainingModelLayer(
      FieldPane fieldPane,
      boolean enable) {

    super(fieldPane, enable);
    Arrays.fill(this.selected, false);
  }

  @Override
  public String getLayerName() {

    return "TrainigModelLayer";
  }

  /**
   * This method just stores the selected ID
   */
  public void selectSoccerObject(int id,
      boolean flag) {

    if (id != SoccerObjectID.MAX_ID) {
      this.selected[id] = flag;
    }
  }

  /**
   * Here, the Players Trainings-Data is painted:
   */
  @Override
  public void draw(Graphics g) {

    if (!this.enable) {
      return;
    }

    // ClientScene scene = fieldPane.getScene();
    TrainingModel tm = WorldModel.getInstance().trainModel;
    // System.out.println("DRAW-ME " + tm);
    if (tm == null) {
      return;
    }

    ((Graphics2D) g).setComposite(AlphaComposite.getInstance(
        AlphaComposite.SRC_OVER, 0.2f));

    // Draw all Players training-data
    Player player = null;
    for (int i = 0; i < SoccerObjectID.BALL; i++) {
      if (!this.selected[i]) {
        continue;
      }

      player = this.fieldPane.getScene().player[i];
      if (player == null) {
        return;
      }

      PlayerTrainingModel ptm = (PlayerTrainingModel) tm.objectTrainingModel[i];

      // draw the trainingsdata
      this.drawPositionModel(g, player, ptm);
      this.drawBodyAngleModel(g, ptm);
      this.drawSpeedModel(g, ptm);
      this.drawPositionMapping(g, ptm);
      this.drawOtherAttributes(g, ptm);

    }

    // draw all Ball training-data
    if (this.selected[SoccerObjectID.BALL]) {
      Ball ball = this.fieldPane.getScene().ball;
      ObjectTrainingModel otm = tm.objectTrainingModel[SoccerObjectID.BALL];

      this.drawPositionModel(g, ball, otm);
      this.drawSpeedModel(g, otm);
      this.drawPositionMapping(g, otm);
    }
    ((Graphics2D) g).setComposite(AlphaComposite.getInstance(
        AlphaComposite.SRC_OVER, 1.0f));
  }

  /**
   * This method visualizes the attributes: -active -roundView (and other)
   * 
   * @param g -
   *          the graphic context
   * @param ptm -
   *          the training-model
   */
  private void drawOtherAttributes(Graphics g,
      PlayerTrainingModel ptm) {

    String s = "";
    if (ptm.isActive()) {
      s += "A";
    }
    if (ptm.isRoundView()) {
      s += "R";
    }

    if (s.length() > 0) {
      ((Graphics2D) g).setComposite(AlphaComposite.getInstance(
          AlphaComposite.SRC_OVER, 0.8f));
      Color old = g.getColor();
      g.setColor(Color2.white);
      Point2f pos = new Point2f();
      pos.x = ptm.getPosition().x + 0.5f;
      pos.y = ptm.getPosition().y + 0.5f;
      this.drawString(g, s, pos);
      g.setColor(old);
      ((Graphics2D) g).setComposite(AlphaComposite.getInstance(
          AlphaComposite.SRC_OVER, 0.2f));
    }
  }

  /**
   * This method draws a small cross to the field, when the mouse-position is
   * over the trainingsButton - indicating the position which maps from the
   * button to the field!
   * 
   * @param g -
   *          graphic-context
   * @param ptm -
   *          the training-model
   */
  private void drawPositionMapping(Graphics g,
      ObjectTrainingModel ptm) {

    if (ptm.getObservePoint() == null) {
      return;
    }
    Color old = g.getColor();
    g.setColor(Color2.black);
    this.drawString(g, "x", ptm.getObservePoint());
    g.setColor(old);
  }

  /**
   * This method draws the position-model. If the model is FIXED, the position
   * is the actual player himself, nothing has to be drawn. If the model is
   * RECTANGULAR or CIRCULAR, the corresponding shape has to be drawn around the
   * Player with an amount of transparency!
   * 
   * @param g -
   *          the graphics-context
   * @param ptm -
   *          the trainings-model of the player
   */
  private void drawPositionModel(Graphics g,
      SoccerObject object,
      ObjectTrainingModel otm) {

    if (otm.getType() == POSITION_TYPE.FIXED) {
      this.drawArrow(g, new Point2f(), otm.getPosition());
      return;
    }
    Color old = g.getColor();
    if (otm instanceof PlayerTrainingModel) {
      if (((Player) object).side == Team.LEFT_SIDE) {
        g.setColor(Color2.yellow);
      }
      else {
        g.setColor(Color2.red);
      }
    }
    else {
      g.setColor(Color2.white);
    }

    if (otm.getType() == POSITION_TYPE.RECTANGULAR) {
      Point2f pos = otm.getPosition();
      // the other way round in soccerscope:
      float ydiff = otm.getX_pos_diff();
      float xdiff = otm.getY_pos_diff();
      this.fillRect(g, new Point2f(pos.x - xdiff, pos.y - ydiff), new Tuple2f(
          (2 * xdiff), (2 * ydiff)));
      // Point2f p = otm.generatePosition();
      // g.setColor(Color2.black);
      // this.fillOval(g, new Point2f(p.x - 1, p.y - 1),
      // new Tuple2f(2,(2)));

    }
    else if (otm.getType() == POSITION_TYPE.CIRCULAR) {

      Point2f pos = otm.getPosition();
      // the other way round in soccerscope
      float ydiff = otm.getX_pos_diff();
      float xdiff = otm.getY_pos_diff();

      this.fillOval(g, new Point2f(pos.x - xdiff, pos.y - ydiff), new Tuple2f(
          (2 * xdiff), (2 * ydiff)));
      // Point2f p = otm.generatePosition();
      // g.setColor(Color2.black);
      // this.fillOval(g, new Point2f(p.x - 1, p.y - 1),
      // new Tuple2f(2,(2)));

    }
    g.setColor(old);
  }

  private void drawBodyAngleModel(Graphics g,
      PlayerTrainingModel ptm) {

    Color old = g.getColor();
    g.setColor(Color2.lightGreen);

    Point2f pos = ptm.getPosition();
    // the other way round in soccerscope
    float ydiff = 3;
    float xdiff = 3;
    float angle = -ptm.getBody_angle();
    float adiff = ptm.getBody_angle_diff();
    this.fillArc(g, new Point2f(pos.x - xdiff, pos.y - ydiff), new Tuple2f(
        (2 * xdiff), (2 * ydiff)), (int) (angle - adiff), (int) (adiff * 2));
    g.setColor(old);
  }

  private void drawSpeedModel(Graphics g,
      ObjectTrainingModel otm) {

    Color old = g.getColor();
    g.setColor(Color2.orangeRed);
    Point2f pos = otm.getPosition();
    // the other way round in soccerscope

    int speedMin = otm.getMin_speed();
    int speedMax = otm.getMax_speed();

    float angle = -otm.getSpeed_angle();
    float adiff = otm.getSpeed_angle_diff();

    // check, if an alignment exists
    if (otm instanceof PlayerTrainingModel) {
      PlayerTrainingModel ptm = (PlayerTrainingModel) otm;
      if (ptm.getAlignSpeedWithBody()) {
        angle = -ptm.getBody_angle();
        adiff = ptm.getBody_angle_diff();
      }
    }

    for (int speedAct = speedMin; speedAct <= speedMax; speedAct += 2) {

      float ydiff = 0.04f * speedAct;
      float xdiff = 0.04f * speedAct;

      // draw min:
      this.drawArc(g, new Point2f(pos.x - xdiff, pos.y - ydiff), new Tuple2f(
          (2 * xdiff), (2 * ydiff)), (int) (angle - adiff), (int) (adiff * 2));
    }
    // Point2f p = otm.generateSpeed();
    // g.setColor(Color2.black);
    // this.fillOval(g, new Point2f(p.x - 1, p.y - 1),
    // new Tuple2f(2,(2)));
    g.setColor(old);
  }

}
